package cn.iocoder.yudao.module.im.service.member;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.im.controller.app.member.vo.AppMemberConversationPageReqVO;
import cn.iocoder.yudao.module.im.controller.app.member.vo.AppMemberConversationSaveReqVO;
import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO;
import cn.iocoder.yudao.module.im.dal.dataobject.member.MemberMessageDO;
import cn.iocoder.yudao.module.im.dal.mysql.group.GroupMapper;
import cn.iocoder.yudao.module.im.dal.mysql.member.MemberMessageMapper;
import cn.iocoder.yudao.module.im.enums.ImGroupTypeEnum;
import cn.iocoder.yudao.module.im.enums.ImMessageContentTypeEnum;
import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import cn.iocoder.yudao.module.mp.api.user.MpUserApi;
import cn.iocoder.yudao.module.mp.api.user.dto.UserMpTemplateMsgSendReqDTO;
import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendTypeEnum;
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.module.trade.api.config.TradeConfigApi;
import cn.iocoder.yudao.module.trade.api.config.dto.TradeConfigRespDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.module.im.controller.admin.member.vo.*;
import cn.iocoder.yudao.module.im.dal.dataobject.member.MemberConversationDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.im.dal.mysql.member.MemberConversationMapper;
import java.time.LocalDateTime;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.im.enums.MessageTemplateConstants.UNREAD_MESSAGE;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;

/**
 * IM会话 Service 实现类
 *
 * @author Jerry
 */
@Service
@Validated
public class MemberConversationServiceImpl implements MemberConversationService {

    @Resource
    private MemberConversationMapper memberConversationMapper;

    @Resource
    private MemberMessageMapper memberMessageMapper;

    @Resource
    private GroupMapper groupMapper;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private MemberPointApi memberPointApi;

    @Resource
    public SocialClientApi socialClientApi;

    @Resource
    private TradeConfigApi tradeConfigApi;

    @Resource
    private MpUserApi mpUserApi;

    @Override
    public Long createMemberConversation(MemberConversationSaveReqVO createReqVO) {
        // 插入
        MemberConversationDO memberConversation = BeanUtils.toBean(createReqVO, MemberConversationDO.class);
        memberConversationMapper.insert(memberConversation);
        // 返回
        return memberConversation.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createMemberConversation(Long loginUserId, AppMemberConversationSaveReqVO createReqVO) {
        if(loginUserId.equals(createReqVO.getUserId())){
            throw exception(CREATE_CONVERSATION_ERROR);
        }
        MemberConversationDO memberConversation = null;
        // 创建一对一会话
        if(ImGroupTypeEnum.PRIVATE.getType().equals(createReqVO.getGroupType())){
           memberConversation = createToOne(loginUserId, createReqVO);
        }

        // 创建一对多会话
        if(ImGroupTypeEnum.PUBLIC.getType().equals(createReqVO.getGroupType())){
            memberConversation = createToMany(loginUserId, createReqVO);
        }

        // 返回
        return memberConversation.getGroupId();
    }

    private MemberConversationDO createToOne(Long loginUserId, AppMemberConversationSaveReqVO createReqVO) {
        MemberConversationDO memberConversation = memberConversationMapper.getMemberConversationByByUserIdAndUserId(loginUserId, createReqVO.getUserId());
        if(memberConversation == null){
            memberConversation = memberConversationMapper.getMemberConversationByByUserIdAndUserId(createReqVO.getUserId(), loginUserId);
            if(memberConversation == null){
                // 创建分组
                GroupDO group = new GroupDO();
                group.setGroupName("一对一");
                group.setGroupType(ImGroupTypeEnum.PRIVATE.getType());
                group.setByUserId(loginUserId);
                group.setUserId(createReqVO.getUserId());
                groupMapper.insert(group);

                // 自己的会话
                memberConversation = new MemberConversationDO();
                memberConversation.setByUserId(loginUserId);
                memberConversation.setUserId(createReqVO.getUserId());
                memberConversation.setGroupId(group.getId());
                memberConversation.setGroupType(group.getGroupType());
                memberConversation.setLastMessageContentType(createReqVO.getLastMessageContentType());
                memberConversation.setLastMessageTime(LocalDateTime.now());
                memberConversation.setStatus(CommonStatusEnum.ENABLE.getStatus());
                memberConversationMapper.insert(memberConversation);

                // 对方的会话
                memberConversation = new MemberConversationDO();
                memberConversation.setByUserId(createReqVO.getUserId());
                memberConversation.setUserId(loginUserId);
                memberConversation.setGroupId(group.getId());
                memberConversation.setGroupType(group.getGroupType());
                memberConversation.setLastMessageContentType(createReqVO.getLastMessageContentType());
                memberConversation.setLastMessageTime(LocalDateTime.now());
                memberConversation.setLastMessageContent("你好");
                memberConversation.setStatus(CommonStatusEnum.ENABLE.getStatus());
                memberConversationMapper.insert(memberConversation);

                MemberUserRespDTO member = memberUserApi.getUser(loginUserId);
                getSelf().sendAsyncMessageToMember(createReqVO.getUserId(), member.getNickname(), group.getId());
            }
        }else{
            memberConversation.setStatus(CommonStatusEnum.ENABLE.getStatus());
            memberConversationMapper.updateById(memberConversation);
        }
        return memberConversation;
    }

    private MemberConversationDO createToMany(Long loginUserId, AppMemberConversationSaveReqVO createReqVO) {
        // 创建分组
        GroupDO group = new GroupDO();
        group.setGroupName("群聊");
        group.setGroupType(ImGroupTypeEnum.PUBLIC.getType());
        group.setByUserId(loginUserId);
        group.setUserId(createReqVO.getUserId());
        groupMapper.insert(group);

        // 自己的会话
        MemberConversationDO memberConversation = new MemberConversationDO();
        memberConversation.setByUserId(loginUserId);
        memberConversation.setUserId(createReqVO.getUserId());
        memberConversation.setGroupId(group.getId());
        memberConversation.setGroupType(group.getGroupType());
        memberConversation.setLastMessageContentType(createReqVO.getLastMessageContentType());
        memberConversation.setLastMessageTime(LocalDateTime.now());
        memberConversation.setDeleted(Boolean.TRUE);
        memberConversationMapper.insert(memberConversation);

        // 对方的会话
        memberConversation = new MemberConversationDO();
        memberConversation.setByUserId(createReqVO.getUserId());
        memberConversation.setUserId(loginUserId);
        memberConversation.setGroupId(group.getId());
        memberConversation.setGroupType(group.getGroupType());
        memberConversation.setLastMessageContentType(createReqVO.getLastMessageContentType());
        memberConversation.setLastMessageTime(LocalDateTime.now());
        memberConversation.setDeleted(Boolean.TRUE);
        memberConversationMapper.insert(memberConversation);
        return  memberConversation;
    }

    @Override
    public void updateMemberConversation(MemberConversationSaveReqVO updateReqVO) {
        // 校验存在
        validateMemberConversationExists(updateReqVO.getId());
        // 更新
        MemberConversationDO updateObj = BeanUtils.toBean(updateReqVO, MemberConversationDO.class);
        memberConversationMapper.updateById(updateObj);
    }

    @Override
    public void updateMemberConversation(AppMemberConversationSaveReqVO updateReqVO) {
        // 校验存在
        validateMemberConversationExists(updateReqVO.getId());
        // 更新
        MemberConversationDO updateObj = BeanUtils.toBean(updateReqVO, MemberConversationDO.class);
        memberConversationMapper.updateById(updateObj);
    }

    @Override
    public void deleteMemberConversation(Long id) {
        // 校验存在
        validateMemberConversationExists(id);
        // 删除
        memberConversationMapper.deleteMemberConversation(id);
    }

    private void validateMemberConversationExists(Long id) {
        if (memberConversationMapper.selectById(id) == null) {
            throw exception(MEMBER_CONVERSATION_NOT_EXISTS);
        }
    }

    @Override
    public MemberConversationDO getMemberConversation(Long id) {
        return memberConversationMapper.selectById(id);
    }

    @Override
    public PageResult<MemberConversationDO> getMemberConversationPage(MemberConversationPageReqVO pageReqVO) {
        return memberConversationMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<MemberConversationDO> getMemberConversationPage(AppMemberConversationPageReqVO pageReqVO) {
        return memberConversationMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUnReadCount(Long messageId) {
        MemberMessageDO memberMessageDO = memberMessageMapper.selectById(messageId);
        Long unreadMessageCount = memberMessageMapper.UnreadMessageCount(memberMessageDO.getGroupId(), memberMessageDO.getReceiveUserId());
        memberConversationMapper.updateUnReadCount(memberMessageDO.getGroupId(), memberMessageDO.getReceiveUserId(), unreadMessageCount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pinnedMemberConversation(AppMemberConversationSaveReqVO updateReqVO) {
        MemberConversationDO conversationDO = memberConversationMapper.selectById(updateReqVO.getId());
        conversationDO.setPinned(updateReqVO.getPinned());
        memberConversationMapper.updateById(conversationDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void slashedMemberConversation(Long id) {
        MemberConversationDO conversationDO = memberConversationMapper.selectById(id);
        conversationDO.setSlashed("1");
        conversationDO.setStatus(CommonStatusEnum.DISABLE.getStatus());
        memberConversationMapper.updateById(conversationDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberConversationRespVO getRandomMemberConversation(Long userId) {
        MemberConversationRespVO conversationRespVO = new MemberConversationRespVO();

        MemberUserRespDTO member = memberUserApi.getUser(userId);

        if(CommonStatusEnum.isDisable(member.getStatus())){
            throw exception(AUTH_LOGIN_USER_DISABLED);
        }

        TradeConfigRespDTO config = tradeConfigApi.getTradeConfig();
        if(!config.getAuthEnabled()){
            if(StringUtils.isBlank(member.getPhoto())){
                throw exception(USER_PHOTO_EMPTY);
            }
        }

        if(!config.getAuthEnabled() && config.getQrcodeEnabled()){
            if(!mpUserApi.getQrcode(getLoginUserId())){
                throw exception(USER_FANS_QRCODE);
            }
        }

        if(member.getMatchTime() == null){
            member.setMatchTime(DateUtil.toLocalDateTime(DateUtil.date()));
            member.setMatchNum(3);
        }else{
            DateTime lastSecondOfDay = DateUtil.endOfDay(new DateTime(member.getMatchTime()));
            if(DateUtil.toLocalDateTime(DateUtil.date()).isAfter(DateUtil.toLocalDateTime(lastSecondOfDay))){
                member.setMatchNum(3);
            }
        }

        Integer point = 100;
        if(member.getMatchNum() < 1){
            if(member.getPoint() < point){
                if(member.getVipEndTime() == null){
                    throw exception(RANDOM_VIP_NOT_EXISTS);
                }else{
                    if(member.getVipEndTime().isBefore(DateUtil.toLocalDateTime(DateUtil.date()))){
                        throw exception(RANDOM_VIP_NOT_EXISTS);
                    }else{
                        point = 0;
                    }
                }
            }
        }

        // 更新在线时间
        memberUserApi.updateUserLogin(userId, getClientIP());

        MemberUserRespDTO randomUser = memberUserApi.getRandomUser(userId);
        if(randomUser == null){
            throw exception(MEMBER_MESSAGE_MORE);
        }
        MemberConversationDO memberConversation = createToRandomOne(userId, randomUser.getId());

        if(member.getMatchNum() < 1 && point > 0){
            // 消耗积分
            memberPointApi.reducePoint(userId, point, MemberPointBizTypeEnum.RANDOM_MSG.getType(), String.valueOf(memberConversation.getId()));

            member.setMatchCount(member.getMatchCount()+1);
            memberUserApi.updateUserMatchNum(member);
        }else{
            // 消耗次数
            member.setMatchNum(member.getMatchNum()-1);
            member.setMatchTime(DateUtil.toLocalDateTime(DateUtil.date()));
            member.setMatchCount(member.getMatchCount()+1);
            memberUserApi.updateUserMatchNum(member);
        }

        // 对方减少次数
        randomUser.setMatchCount(randomUser.getMatchCount()-1);
        if(randomUser.getMatchCount() < 0){
            randomUser.setMatchCount(0);
        }
        memberUserApi.updateUserMatchNum(randomUser);

        conversationRespVO.setGroupId(memberConversation.getGroupId());
        conversationRespVO.setUserId(randomUser.getId());

        getSelf().sendAsyncMessageToMember(randomUser.getId(), member.getNickname(), memberConversation.getGroupId());
        // 返回
        return conversationRespVO;
    }

    /**
     * 微信小程序订阅消息
     * @param userId
     */
    @Async
    public void sendAsyncMessageToMember(Long userId, String nickname, Long groupId) {
        // 有未读消息
        MemberConversationDO conversationDO = memberConversationMapper.getMemberConversationByByUserIdAndGroupId(userId, groupId);
        if(conversationDO.getUnreadMessageCount() < 2){
            boolean flag = socialClientApi.sendWxaSubscribeMessage(new SocialWxaSubscribeMessageSendReqDTO()
                    .setUserId(userId).setUserType(UserTypeEnum.MEMBER.getValue())
                    .setTemplateTitle(UNREAD_MESSAGE)
                    .setPage("pages/tabbar/index") // 首页
                    .addMessage("thing1", "你的朋友给你发了信息，点击查看") // 回信内容
                    .addMessage("time2", DateUtil.now())); // 互信时间
            if(!flag){
                mpUserApi.sendTemplateMsg(new UserMpTemplateMsgSendReqDTO()
                        .setUserId(userId)
                        .setUserType(UserTypeEnum.MEMBER.getValue())
                        .setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
                        .setMsgType(MpMessageSendTypeEnum.UNREAD_MSG.getType())
                        .setPage("pages/tabbar/index") // 首页
                        .addMessage("first", "您好，您收到一条私信回复")
                        .addMessage("keyword1", nickname)
                        .addMessage("keyword2", DateUtil.now())
                        .addMessage("keyword3", "您好，您收到一条私信回复")
                        .addMessage("remark", "本条信息是站内信通知！点击查看详情"));
            }
        }
    }

    private MemberConversationDO createToRandomOne(Long userId, Long receiveUserId) {
        MemberConversationDO memberConversation = memberConversationMapper.getMemberConversationByByUserIdAndUserId(userId, receiveUserId);
        if(memberConversation == null){
            memberConversation = memberConversationMapper.getMemberConversationByByUserIdAndUserId(receiveUserId, userId);
            if(memberConversation == null){
                // 创建分组
                GroupDO group = new GroupDO();
                group.setGroupName("一对一");
                group.setGroupType(ImGroupTypeEnum.PRIVATE.getType());
                group.setByUserId(userId);
                group.setUserId(receiveUserId);
                group.setIsMatch(true);
                groupMapper.insert(group);

                // 自己的会话
                memberConversation = new MemberConversationDO();
                memberConversation.setByUserId(userId);
                memberConversation.setUserId(receiveUserId);
                memberConversation.setGroupId(group.getId());
                memberConversation.setGroupType(group.getGroupType());
                memberConversation.setLastMessageContentType(ImMessageContentTypeEnum.TEXT.getType());
                memberConversation.setLastMessageTime(LocalDateTime.now());
                memberConversation.setStatus(CommonStatusEnum.ENABLE.getStatus());
                memberConversation.setLastMessageContent("匹配成功，可以免费聊天");
                memberConversationMapper.insert(memberConversation);

                // 对方的会话
                memberConversation = new MemberConversationDO();
                memberConversation.setByUserId(receiveUserId);
                memberConversation.setUserId(userId);
                memberConversation.setGroupId(group.getId());
                memberConversation.setGroupType(group.getGroupType());
                memberConversation.setLastMessageContentType(ImMessageContentTypeEnum.TEXT.getType());
                memberConversation.setLastMessageTime(LocalDateTime.now());
                memberConversation.setStatus(CommonStatusEnum.ENABLE.getStatus());
                memberConversation.setLastMessageContent("匹配成功，可以免费聊天");
                memberConversationMapper.insert(memberConversation);
            }
        }else{
            memberConversation.setStatus(CommonStatusEnum.ENABLE.getStatus());
            memberConversationMapper.updateById(memberConversation);
        }
        return memberConversation;
    }

    private MemberConversationServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}